<template>
    <UxDialog :visible="visible" @close="onClose()">

        <div class="uploader-card" v-if="uploader" :error="uploader.error ? 'error' : ''">
            <h2>Upload file</h2>
            <h3 v-text="uploader.file ? uploader.file.name : 'uploading'"></h3>
            <h4 v-text="uploaderText"></h4>
            <figure>
                <img v-if="uploader.image" :src="uploader.image.src"
                     :style="$fiexImage(uploader.image.width, uploader.image.height, 1)">
                <img v-else-if="uploader.error" class="uploader-error" src="@/assets/images/error.png">
                <UxLoading v-else />
            </figure>
            <span>
                <em v-text="uploader.error" v-if="uploader.error"></em>
                <em v-text="uploader.percent + '%'" v-else></em>
            </span>
            <strong>
                <b :style="{ width: uploader.percent + '%' }"></b>
            </strong>
            <button @click="onClose()">Cancel</button>
        </div>

        <div class="uploader" v-else>
            <!-- 文件添加框 -->
            <!-- <div ref="filebox" class="filebox"></div> -->

            <div class="drag-box" @dragenter="active = true" @dragleave="active = false"
                 @dragover="fileDragover($event)" @drop="fileDrop($event)" :class="{ active: active }">
                <svg-icon name="user-files-drag" />
                <span>Drop dst file here</span>
            </div>

            <div class="or"></div>

            <div class="input">
                <label>
                    <svg-icon name="user-files-upload" />
                    <span>Choose files</span>
                    <input type="file" multiple accept=".dst,.DST" @change="fileClick($event)">
                </label>
            </div>

            <p>
                <svg-icon name="notify2" />
                <span>DST format, max 50 MB, max 12″×12″</span>
            </p>

        </div>
    </UxDialog>
</template>
<script>
import Md5 from "js-md5";
import { mapGetters } from "vuex";
import { readDst, getBase64ByBuffer } from "@/utils/EmbroideryDst.js";
import { writeCanvas } from "@/utils/EmbroideryCanvas.js";

export default {
    props: {
        value: { type: Boolean, default: () => false },
        type: { type: String, default: () => 'drag' },
        uploaded: { type: Array, default: () => [] },
    },
    data () {
        return {
            active: false,
            uploader: null,
            error: null,
        };
    },
    computed: {
        ...mapGetters({
            isLogin: "getIsLogin",
        }),
        ...mapGetters("user", {
            userInfo: "getUserInfo",
        }),
        visible: {
            get () { return this.value },
            set (val) { this.$emit("input", val); }
        },

        uploaderText () {
            if (this.uploader && this.uploader.width > 1 && this.uploader.height > 1) {
                const size = [this.uploader.width, this.uploader.height].map(i => (i * 0.1 * 0.0394).toFixed(1)).join(' × ') + ' in '
                const stitches = '/ ' + this.uploader.stitches_count + ' stitches'
                return size + stitches
            } else {
                return ''
            }
        }
    },

    methods: {

        // 拖拽上传
        fileDragover (event) {
            event.preventDefault()
        },
        fileDrop (event) {
            event.preventDefault()
            this.active = false;
            this.uploadFiles(Array.prototype.slice.call(event.dataTransfer.files))
        },
        fileClick (event) {
            const files = Array.prototype.slice.call(event.target.files)
            this.uploadFiles(files)
            event.target.value = null;
        },

        // 手动上传
        startUpload (callback) {
            this.selectFile().then(file => this.uploadFiles([file])).then(res => {
                this.uploader && callback && callback(res[0])
                this.onClose()
            }).catch(err => {
                // console.log(err);
            })
        },

        onClose () {
            this.visible = false
            this.uploader = null
        },

        // 上传
        uploadFiles (files) {

            // 01.图片预览失败: Network error. Please try again.
            // 02.不支持的文件格式（只支持png，jpeg，jpg）: Incorrect file format.
            // 03.图片不能大于50M: Uploaded image exceeds 50MB limit.
            // 04.图片上传失败（超过三次）: Network error. Please try again.
            // 05.生成缩略图失败: Network error. Please try again.
            // 06.图片绑定用户失败:  Network error. Please try again.

            const time = new Date().getTime();
            const options = []
            const promises = files.map((file, index) => {
                const file_name = file.name.replace(/\.\w+$/, '')
                const file_type = file.name.slice(file_name.length + 1)
                const option = {
                    type: "uploading",
                    id: time + "-" + index,
                    file_type: file_type.toLowerCase(),
                    file_name: file_name,
                    file_url: "",
                    img_url: '',
                    width: 1,
                    height: 1,
                    top: 0,
                    bottom: 0,
                    left: 0,
                    right: 0,
                    line_color: '',
                    file: file,
                    pattern: null,
                    image: null,
                    canvas: null,
                    stitches: '',
                    stitches_count: 0,
                    percent: 5,
                    color_unedited: 0,
                    error: '',
                };


                options.push(option)

                return this.getFileInfo(option)
                    .then(() => this.type != 'card' || this.uploader ? this.getFilePreview(option) : Promise.reject('Canceled'))
                    .then(() => this.type != 'card' || this.uploader ? this.uploadDstToOSS(option) : Promise.reject('Canceled'))
                    .then(() => this.type != 'card' || this.uploader ? this.bindUser(option) : Promise.reject('Canceled'))
                    .then(() => {
                        // 成功
                        option.type = "";
                        option.percent = 100;
                        return this.type != 'card' || this.uploader ? option : Promise.reject('Canceled')
                    }).catch(err => {
                        // 失败
                        option.type = "error";
                        option.error = err || 'Network error. Please try again.';

                        // 01.图片预览失败: File upload failed.
                        // 02.不支持的文件格式（只支持png，jpeg，jpg）: Incorrect file format.
                        // 03.图片不能大于50M: Uploaded image exceeds 50MB limit.
                        // 04.图片上传失败（超过三次）: Network error. Please try again.
                        // 05.生成缩略图失败: File upload failed.
                        // 06.图片绑定用户失败:  File upload failed.

                        const map = new Map([
                            ['Incorrect file format.', 'File parsing failed, please check the file and try again.'],
                            ['Uploaded image exceeds 50MB limit.', 'Uploaded images should not exceed 50MB.'],
                        ])
                        option.error = map.get(option.error) || option.error;

                        // const notify = '"' + option.file_name + '" upload failed. ' + (map.get(option.error) || '')


                        return this.type == 'card' && Promise.reject(option.err);
                    })

            })

            if (promises.length == 0 || options.length == 0) {
                this.visible = false;
                this.uploader = null;
                return Promise.reject('No file selected')
            } else if (this.type == 'card') {
                // 卡片式上传
                this.visible = true;
                this.uploader = options[0];
                return Promise.all(promises)
            } else {
                // 如果正在搜索中，则退出搜索
                if (this.$parent.form.name) {
                    this.$parent.keywords = '';
                    this.$parent.getSearching()
                }
                this.visible = false;
                this.uploader = null;
                this.$emit('update:uploaded', [...options, ...this.uploaded]);
                return Promise.all(promises).then(() => this.$emit('reload'))
            }

        },

        // 选中文件上传
        selectFile () {

            return new Promise((resolve, reject) => {
                let filebox = document.querySelector('.emb-filebox');
                let input = null;

                if (filebox) {
                    input = filebox.querySelector('input');
                } else {
                    filebox = document.createElement('div');
                    filebox.setAttribute('class', 'emb-filebox');
                    filebox.setAttribute('style', ' position: absolute;left: 0;top: 0;width: 0;height: 0;overflow: hidden;opacity: 0;');
                    filebox.innerHTML = '<input type="file" accept=".dst,.DST">';
                    document.body.appendChild(filebox);
                    input = filebox.querySelector('input');
                }

                const focusEvent = (event) => {
                    // 有可能有延时
                    window.removeEventListener('focus', focusEvent)
                    setTimeout(() => {
                        if (!input.lock) {
                            reject('Selected cancel', input.files.length)
                            // document.getElementById(input.id) && input.remove();
                        } else {
                            // input.remove();
                        }
                    }, 500)
                }

                input.onchange = () => {
                    if (input.files && input.files[0]) {
                        resolve(input.files[0])
                    } else {
                        reject('No file select');
                    }
                    input.lock = true;
                    input.value = null;
                    filebox.remove();
                    // filebox.innerHTML = html;
                }

                // window.addEventListener('focus', focusEvent)
                input.click();
            })
        },


        // 获取文件信息
        getFileInfo (option) {

            const maxsize = 1024 * 1024 * 50; // 不能上传超过50M的图片
            if (option.file.size > maxsize) {
                return Promise.reject('Uploaded image exceeds 50MB limit.')
            } else if (['dst'].indexOf(option.file_type) < 0) {
                // 不支持的格式
                return Promise.reject('Incorrect file format.')
            } else {
                return new Promise((resolve, reject) => {
                    const reader = new FileReader();
                    reader.onloadend = (event) => {

                        const max = 12 * 254
                        const buffer = event.target.result
                        const pattern = readDst(buffer)
                        const threads = pattern.threads.filter(i => ['CO:', 'ST:'].indexOf(i.name) > 0)
                        const bounds = pattern.getBounds()

                        if (threads.length == 0 || threads.find(i => (parseInt(i.value) || 0) <= 0)) {
                            // 有异常
                            reject('Incorrect file format.')
                        } else if (bounds.width > max || bounds.height > max) {
                            // 超出大小
                            reject('Design size is too large for the embroidery frame.')

                        } else if (pattern.colors.length > 30) {
                            reject('Color change limit exceeded.')

                        } else {
                            getBase64ByBuffer(buffer).then(base64 => {

                                option.pattern = pattern
                                option.width = bounds.width;
                                option.height = bounds.height;
                                option.left = bounds.left;
                                option.right = bounds.right;
                                option.top = bounds.top;
                                option.bottom = bounds.bottom;
                                option.line_color = pattern.getColorCodes();
                                option.stitches = base64
                                option.stitches_count = pattern.stitches.length
                                resolve(option)

                            }).catch(err => reject('Incorrect file format.'))
                        }

                    }
                    reader.abort = (err) => reject('Incorrect file format.');
                    reader.onerror = (err) => reject('Incorrect file format.');
                    reader.readAsArrayBuffer(option.file);
                })
            }

        },

        getFilePreview (option) {
            return new Promise((resolve, reject) => {
                const canvas = writeCanvas(option.pattern.stitches, option.pattern.colors)
                const img = new Image();
                img.onload = () => {
                    option.image = img;
                    option.canvas = canvas
                    resolve(option);
                };
                img.onerror = (error) => { reject('File parsing failed, please check the file and try again.') };
                img.src = canvas.toDataURL();
            })
        },

        // 上传版带文件
        uploadDstToOSS (option) {

            const email = (this.userInfo || {}).email;
            const folder = email ? Md5(email) : 'noemail';
            const path = (this.isLogin ? 'data/pod/file/' + folder : 'data/zx/design/nologin').replace(/\/+$/, '') + '/';

            const time = new Date().getTime();
            const random = Math.random().toFixed(10).substr(2);

            // 上传版带
            const uploadDst = new Promise((resolve, reject) => {

                const request = {
                    file: option.file,
                    name: time + "-" + random + "." + option.file_type,
                    path: path,
                    onprogress (event) {
                        option.percent = 5 + parseInt(0.9 * event.percent);
                    },
                };

                this.$uploadToOSS(request, response => {
                    if (response.code === 0 && response.data) {
                        option.file_url = response.data || '';
                        resolve(option);
                    } else {
                        reject(response.msg || "Network error. Please try again.");
                    }
                })
            })

            const uploadThumb = new Promise((resolve, reject) => {

                option.canvas.toBlob(blob => {
                    const request = {
                        file: blob,
                        name: time + "-" + random + ".png",
                        path: path,
                        onprogress (event) {
                            option.percent = 5 + parseInt(0.9 * event.percent);
                        },
                    };
                    this.$uploadToOSS(request, response => {
                        if (response.code === 0 && response.data) {
                            option.img_url = response.data || '';
                            resolve(option);
                        } else {
                            reject(response.msg || "Network error. Please try again.");
                        }
                    })

                }, "image/png", 1)


            })

            return Promise.all([uploadDst, uploadThumb])
        },

        //  绑定用户图片
        bindUser (option) {

            if (!this.isLogin) {
                option.id = '';
                return Promise.resolve(option)
            } else {
                // 绑定
                const request = {
                    file_name: option.file_name,
                    file_url: option.file_url,
                    file_type: option.file_type,
                    img_url: option.img_url,
                    width: option.width,
                    height: option.height,
                    left: option.left,
                    top: option.top,
                    right: option.right,
                    bottom: option.bottom,
                    line_color: option.line_color,
                    stitches_count: option.stitches_count,
                    stitches: option.stitches,
                };
                return new Promise((resolve, reject) => {
                    this.$http('Material.addEmbBind', request).then(result => {
                        if (!result || result.code !== 0) {
                            return reject("Network error. Please try again.");
                        } else {
                            option.id = result.data;
                            return resolve(option);
                        }
                    }).catch(error => {
                        reject("Network error. Please try again.");
                    })
                });
            }


        },


    },
};
</script>
<style lang="scss" scoped>
.uploader {
    padding: 40px 24px 33px;

    .drag-box {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        width: 460px;
        height: 200px;
        background: #fafafa;
        border-radius: 6px;
        border: 1px dashed #cccccc;

        svg {
            width: 32px;
            height: 32px;
            pointer-events: none;
        }

        span {
            margin-top: 4px;
            font-size: 14px;
            font-family: Roboto-Regular, Roboto;
            font-weight: 400;
            color: #9e9e9e;
            line-height: 16px;
            pointer-events: none;
        }

        &.active {
            border-color: #239ac2;
            background-color: rgba(237, 251, 255, 0.4);

            span {
                color: #239ac2;
            }

            svg {
                color: #239ac2;
            }
        }
    }

    .or {
        position: relative;
        font-size: 14px;
        font-family: Roboto-Regular, Roboto;
        font-weight: 400;
        color: #9e9e9e;
        line-height: 16px;
        height: 16px;
        margin-top: 32px;

        &::before {
            content: '';
            position: absolute;
            left: 0;
            top: 50%;
            right: 0;
            height: 1px;
            background: #f0f0f0;
            transform: translateY(-50%);
        }

        &::after {
            content: 'Or';
            position: absolute;
            width: 40px;
            background-color: #fff;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
        }
    }

    .input {
        margin-top: 32px;
        position: relative;
        display: flex;
        justify-content: center;

        label {
            width: 260px;
            height: 40px;
            position: relative;
            overflow: hidden;
            background: #ea4c89;
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: pointer;

            &:hover {
                background: #c94175;
            }
        }

        input {
            position: absolute;
            right: 0;
            top: 0;
            width: 300%;
            height: 300%;
            font-size: 99em;
            opacity: 0;
            cursor: pointer;
        }

        span {
            font-size: 14px;
            font-family: Roboto-Medium, Roboto;
            font-weight: 500;
            color: #ffffff;
        }

        svg {
            width: 18px;
            height: 18px;
            margin-right: 4px;
            color: #fff;
        }
    }

    &>p {
        margin-top: 32px;
        display: flex;
        justify-content: center;
        align-items: center;

        svg {
            width: 14px;
            height: 14px;
            border-radius: 14px;
            color: #a8a8a8;
            margin-right: 4px;
        }

        span {
            font-size: 12px;
            font-family: Roboto-Regular, Roboto;
            font-weight: 400;
            color: #757575;
            line-height: 14px;
        }
    }
}

.uploader-card {
    z-index: 1;
    width: 368px;
    box-sizing: border-box;
    padding: 24px;
    background: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: 8px;

    &>h2 {
        font-size: 16px;
        font-family: Roboto-Medium, Roboto;
        font-weight: 500;
        color: #000000;
        line-height: 18px;
    }

    h3 {
        margin-top: 12px;
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-align: center;
        font-size: 14px;
        font-family: Roboto-Regular, Roboto;
        font-weight: 400;
        color: #000000;
        line-height: 16px;
    }

    h4 {
        margin-top: 8px;
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        text-align: center;
        font-family: Roboto, Roboto;
        font-weight: 400;
        font-size: 14px;
        color: #555555;
        line-height: 16px;
        line-height: 16px;
    }

    &>figure {
        width: 100%;
        margin-top: 14px;
        position: relative;
        background: #f1f1f1;

        &::before {
            content: '';
            display: block;
            padding-bottom: 100%;
        }

        img {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;

            &.uploader-error {
                width: 88px;
                height: 88px;
                left: 50%;
                top: 50%;
                transform: translate(-50%, -50%);
            }
        }
    }

    &>span {
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        display: block;
        text-align: center;
        font-size: 12px;
        color: #000000;
        line-height: 14px;
        height: 14px;
        margin-top: 10px;
        font-weight: normal;
        color: #000000;
    }

    &>strong {
        margin-top: 6px;
        display: block;
        width: 100%;
        height: 10px;
        border-radius: 6px;
        display: block;
        position: relative;
        background-color: #ebebeb;
        margin-top: 4px;

        b {
            position: absolute;
            left: 0;
            top: 0;
            height: 100%;
            border-radius: 6px;
            background-color: #43b9e2;
        }
    }

    button {
        width: 160px;
        margin-top: 24px;
    }

    &[error='error'] {
        &>span em {
            color: #f44336;
        }

        &>strong b {
            background-color: #f44336;
        }
    }
}
</style>
